#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/io.h>
#include <linux/uaccess.h>
#include "myled.h"


int major = 0;  // 主设备号
char kbuf[2] = {0};

volatile unsigned int *rcc_virl_addr;
volatile gpio_t *gpioe_virl_base_addr;
volatile gpio_t *gpiof_virl_base_addr;

int myled_open (struct inode *inode, struct file *file_accessed)
{
    printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
    return 0;
}
ssize_t myled_read (struct file *file, char __user *ubuf, size_t size, loff_t *offset)
{
    int ret;
    printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
    return size;
}
/*
    指定led灯控制的协议
    kbuf[0]  :  1 ---> led1   2 ---> led2   3 ---> led3
    kbuf[1]  :  0 ---> off    1 ---> on
*/
ssize_t myled_write (struct file *file, const char __user *ubuf, size_t size, loff_t *offset)
{
    int ret;
    printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
    // 校验大小
    if (size > sizeof(kbuf)) 
        size = sizeof(kbuf);
    // 从用户空间的数据拷贝到内核空间
    ret = copy_from_user(kbuf, ubuf, size);
    if (ret) 
    {
        printk("copy data failed\n");
        return  -EIO;// 失败返回错误码
    }
    printk("leds = %d, status = %d\n", kbuf[0], kbuf[1]);
    switch(kbuf[0])
    {
        case 1:
            if (kbuf[1] == 1) {
                gpioe_virl_base_addr->BSRR |= (0x1 << 10);
            } else {
                gpioe_virl_base_addr->BRR |= (0x1 << 10);
            }
        break;
        case 2:
            if (kbuf[1] == 1) {
                gpiof_virl_base_addr->BSRR |= (0x1 << 10);
            } else {
                gpiof_virl_base_addr->BRR |= (0x1 << 10);
            }
        break;
        case 3:
            if (kbuf[1] == 1) {
                gpioe_virl_base_addr->BSRR |= (0x1 << 8);
            } else {
                gpioe_virl_base_addr->BRR |= (0x1 << 8);
            }
        break;
    }
    return size;
}
int myled_close (struct inode *inode, struct file *file)
{
    printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
    return 0;
}
// 定义操作方法结构体的变量，并对成员进行初始化
struct file_operations fops = {
    .open = myled_open,
    .read = myled_read,
    .write = myled_write,
    .release = myled_close,
};

int led_init(void)
{
    // 完成物理地址到虚拟地址的映射
    rcc_virl_addr = ioremap(RCC_PHY_ADDR, 4);
    if (rcc_virl_addr == NULL) {
        printk("phy addr to virl addr failed\n");
        return -ENOMEM;
    }

    gpioe_virl_base_addr = ioremap(GPIOE_BASE_ADDR, sizeof(gpio_t));
    if (gpioe_virl_base_addr == NULL) {
        printk("phy addr to virl addr failed\n");
        return -ENOMEM;
    }
    
    gpiof_virl_base_addr = ioremap(GPIOF_BASE_ADDR, sizeof(gpio_t));
    if (gpiof_virl_base_addr == NULL) {
        printk("phy addr to virl addr failed\n");
        return -ENOMEM;
    }
    // GPIOE和GPIOF外设时钟的使能
    *rcc_virl_addr = (0x3 << 4);
    // LED1灯的初始化
    gpioe_virl_base_addr->MODER &= (~(0x3 << 20));
    gpioe_virl_base_addr->MODER |= (0x1 << 20);
    gpioe_virl_base_addr->OTYPER &= (~(0x1 << 10));
    gpioe_virl_base_addr->OSPEEDR &= (~(0x3 << 20));
    gpioe_virl_base_addr->PUPDR &= (~(0x3 << 20));
    gpioe_virl_base_addr->ODR &= (~(0x1 << 10));
    // LED2灯的初始化
    gpiof_virl_base_addr->MODER &= (~(0x3 << 20));
    gpiof_virl_base_addr->MODER |= (0x1 << 20);
    gpiof_virl_base_addr->OTYPER &= (~(0x1 << 10));
    gpiof_virl_base_addr->OSPEEDR &= (~(0x3 << 20));
    gpiof_virl_base_addr->PUPDR &= (~(0x3 << 20));
    gpiof_virl_base_addr->ODR &= (~(0x1 << 10));
    // LED3灯的初始化
    gpioe_virl_base_addr->MODER &= (~(0x3 << 16));
    gpioe_virl_base_addr->MODER |= (0x1 << 16);
    gpioe_virl_base_addr->OTYPER &= (~(0x1 << 8));
    gpioe_virl_base_addr->OSPEEDR &= (~(0x3 << 16));
    gpioe_virl_base_addr->PUPDR &= (~(0x3 << 16));
    gpioe_virl_base_addr->ODR &= (~(0x1 << 8));
    return 0;
}

void led_delInit(void)
{
    iounmap(gpioe_virl_base_addr);
    iounmap(gpiof_virl_base_addr);
    iounmap(rcc_virl_addr);
}
static int __init myled_init(void)
{
    int ret;
    printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
    // 注册字符设备
    major = register_chrdev(0, CNAME, &fops);
    if (major < 0) {
        printk("register char device failed!\n");
        return major;
    }
    printk("register char device successed, major = %d\n", major);

    ret = led_init();
    if (ret != 0) {
        return ret;
    }

    return 0;
}

static void __exit myled_exit(void)
{
    printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
    // 先销毁虚拟的映射的地址
    led_delInit();
    // 销毁字符设备
    unregister_chrdev(major, CNAME);
}

module_init(myled_init);
module_exit(myled_exit);
MODULE_LICENSE("GPL");
// 指定驱动的作者或者邮箱
MODULE_AUTHOR("zhoukai zhouk_bj@hqyj.com");